package server;

import static org.junit.Assert.*;

import java.sql.SQLException;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * The testing class for MYSQLComm, checking all the program's interface to the MYSQL DB is OK.
 */
public class MYSQLTest {

	//please make sure you have a TestFW database with the correct scheme.
	
	static MYSQLComm mysql;
	
	//static String hostname = "192.168.0.31";
	//static String hostname = "132.68.36.186";
	//static String hostname = "192.168.147.128";
	static String hostname = "127.0.0.1";
	static String dbname = "TestFW";
	static String username = "root";
	static String password = "";

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		try {
			mysql = new MYSQLComm(hostname, dbname, username, password, true);
		} catch (SQLException e)
		{
			System.err.println ("Error message: " + e.getMessage());
			System.err.println ("Error number: " + e.getErrorCode());		
			throw e;
		}
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
		mysql = null;
		System.gc();
	}

	@Test
	public void testAddRule() {
		try {
			Rule rule = new Rule(1, null, 6667, Rule.permissionOpt.ALLOW);
			mysql.addRule("tfsbdfbdfest", rule);
		} catch (SQLException e) {
			if (e.getErrorCode() != 1146)
				fail("An error has occoured: " + e.getMessage() + " (" + e.getErrorCode() + ")");
		}
	}
	
	@Test
	public void testDeleteRule() {
		try {
			Rule rule = new Rule(1, null, 6667, Rule.permissionOpt.ALLOW);
			mysql.addRule("tfsbdfbdfest", rule);
		} catch (SQLException e) {
			if (e.getErrorCode() != 1146)
				fail("An error has occoured: " + e.getMessage() + " (" + e.getErrorCode() + ")");
		}
		try {
			mysql.deleteRule("ActiveRules_In", 1);
			mysql.deleteRuleComplete(true);
		} catch (SQLException e) {
			try {
				mysql.deleteRuleComplete(false);
				fail("Couldn't delete a rule");
			} catch (SQLException e1) {
				fail("Couldn't delete a rule");
			}
		}
	}
	
	@Test
	public void testGetRules() {
		Rule rule1 = null, rule2 = null;
		try {
			rule1 = new Rule(1, null, 6667, Rule.permissionOpt.ALLOW);
			mysql.addRule("ActiveRules_In", rule1);
		} catch (SQLException e) {
			if (e.getErrorCode() != 1146)
				fail("An error has occoured: " + e.getMessage() + " (" + e.getErrorCode() + ")");
		}
		try {
			rule2 = new Rule(1, null, 6667, Rule.permissionOpt.ALLOW);
			mysql.addRule("ActiveRules_In", rule2);
		} catch (SQLException e) {
			if (e.getErrorCode() != 1146)
				fail("An error has occoured: " + e.getMessage() + " (" + e.getErrorCode() + ")");
		}
		try {
			Rule[] rules = mysql.getRules("ActiveRules_In");
			boolean found = false;
			if (!rules[0].equals(rule1))
				fail("Wrong rule found");
			if (!rules[1].equals(rule2))
				fail("Wrong rule found");
		} catch (SQLException e) {
			fail("An error has occoured: " + e.getMessage() + " (" + e.getErrorCode() + ")");
		}
	}
		
	/**
	 * Checks all the rules abilities, including adding, removing and listing them.
	 */
	@Test
	public void testAddRuleandDeleteRule() {
		// try adding in a non-existent table.
		try {
			Rule rule = new Rule(1, null, 6667, Rule.permissionOpt.ALLOW);
			mysql.addRule("ActiveRules_In", rule);
		} catch (SQLException e) {
			if (e.getErrorCode() != 1146)
				fail("An error has occoured: " + e.getMessage() + " (" + e.getErrorCode() + ")");
		}
		Rule rule = null;
		int size = 0;
		// add an valid IP Rule.
		try {
			rule = new Rule(1, null, 6667, Rule.permissionOpt.ALLOW);
			mysql.addRule("ActiveRules_In", rule);
		} catch (SQLException e) {
			fail("An error has occoured: " + e.getMessage() + " (" + e.getErrorCode() + ")");
		}
		// check if the rule exists.
		try {
			Rule[] rules = mysql.getRules("ActiveRules_In");
			size = rules.length;
			boolean found = false;
			for (Rule ruleList : rules)
			{
				if (rule.index == ruleList.index)
				{
					found = true;
					if (!rule.equals(ruleList))
					{
						fail("Not correct rule");
					}
					break;
				}
			}
			if (!found)
				fail("Not found");
		} catch (SQLException e) {
			fail("An error has occoured: " + e.getMessage() + " (" + e.getErrorCode() + ")");
		}
		// delete all rules.
		try {
			while (size != 0)
			{
				mysql.deleteRule("ActiveRules_In", size);
				mysql.deleteRuleComplete(true);
				size--;
			}
		} catch (SQLException e) {
			try {
				mysql.deleteRuleComplete(false);
			} catch (SQLException e1) {
				fail("An error has occoured: " + e.getMessage() + " (" + e.getErrorCode() + ")");
			}
			fail("An error has occoured: " + e.getMessage() + " (" + e.getErrorCode() + ")");
		}
		// check if any rule exists.
		try {
			Rule[] rules = mysql.getRules("ActiveRules_In");
			if (rules.length != 0)
				fail("Not empty");
		} catch (SQLException e) {
			fail("An error has occoured: " + e.getMessage() + " (" + e.getErrorCode() + ")");
		}
	}

	@Test
	public void testGetPasswordWrongUser() {
		try {
			Password pass = mysql.getPassword("erkjfherjfherferf");
		} catch (SQLException e) {
			if (!e.getMessage().equals("No such user"))
				fail("User shouldn't exist");
		}
	}

	@Test
	public void testGetPasswordSimple() {
		try {
			Password pass = mysql.getPassword("FW_S");
			if (!pass.password.equals("0"))
				fail("Wrong password");
			if (!pass.user.equals("FW_S"))
				fail("Wrong username");
			if (!pass.type.equals(Password.typeOpt.SIMPLE))
				fail("Wrong permissions");
		} catch (SQLException e) {
			fail("Couldn't get simple user");
		}
	}

	@Test
	public void testGetPasswordExpert() {
		try {
			Password pass = mysql.getPassword("FW_E");
			if (!pass.password.equals("1"))
				fail("Wrong password");
			if (!pass.user.equals("FW_E"))
				fail("Wrong username");
			if (!pass.type.equals(Password.typeOpt.EXPERT))
				fail("Wrong permissions");
		} catch (SQLException e) {
			fail("Couldn't get simple user");
		}
	}

	@Test
	public void testAddProtocolandGetProtocol() {
		try {
			mysql.deleteProtocol("test");
		} catch (SQLException e) {
		}
		Protocol prot = new Protocol("test", "1", "rgewr");
		try {
			mysql.addProtocol(prot);
		} catch (SQLException e) {
			fail("Error adding protocol");
		}
		try {
			Protocol protget = mysql.getProtocol("test");
			if (!protget.equals(prot))
				fail("Not same protocol");
		} catch (SQLException e) {
			fail("Error getting protocol");
		}
		try {
			mysql.addProtocol(prot);
		} catch (SQLException e) {
			if (e.getErrorCode() != 1062)
				fail("Error, allowing to add same protocol twice?");
		}
	}
	
	@Test
	public void testDeleteProtocol() {
		try {
			mysql.deleteProtocol("test");
		} catch (SQLException e) {
		}
		Protocol prot = new Protocol("test", "1", "rgewr");
		try {
			mysql.addProtocol(prot);
		} catch (SQLException e) {
			fail("Erorr adding protocol");
		}
		try {
			mysql.deleteProtocol("test");
		} catch (SQLException e) {
			fail("Error deleting protocol");
		}
	}

	@Test
	public void testUpdateProtocol() {
		try {
			mysql.deleteProtocol("test");
		} catch (SQLException e) {
		}
		Protocol prot = new Protocol("test", "1", "rgewr");
		try {
			mysql.addProtocol(prot);
		} catch (SQLException e) {
			fail("Error adding protocol");
		}
		try {
			mysql.updateProtocol(prot);
		} catch (SQLException e) {
			fail("Error updating protocol");
		}
	}

	@Test
	public void testGetProtocols() {
		Protocol[] protocols = null;
		try {
			protocols = mysql.getProtocols();
		} catch (SQLException e) {
			fail("Couldn't get list of protocols");
		}
		for (Protocol protocol : protocols) {
			try {
				mysql.deleteProtocol(protocol.protocol);
			} catch (SQLException e) {
				fail("Couldn't delete an existing protocol");
			}
		}
		Protocol prot = new Protocol("test", "1", "rgewr");
		try {
			mysql.addProtocol(prot);
		} catch (SQLException e) {
			fail("Error adding protocol");
		}
		Protocol prot2 = new Protocol("blah", "1", "2");
		try {
			mysql.addProtocol(prot2);
		} catch (SQLException e) {
			fail("Error adding protocol");
		}
		try {
			protocols = mysql.getProtocols();
		} catch (SQLException e) {
			fail("Couldn't get list of protocols");
		}
		if (protocols.length != 2)
			fail("Wrong protocol list");
		for (Protocol protocol : protocols) {
			if (!protocol.equals(prot) && !protocol.equals(prot2))
				fail("Protocol list isn't correct");
		}
	}

	@Test
	public void testGetProtocol() {
		try {
			mysql.getProtocol("ergergerogherg");
			fail("Got an invalid protocol name");
		} catch (SQLException e) {
		}
	}

	@Test
	public void testCreateRuleSet() {
		try {
			mysql.deleteRuleSet("test");
		} catch (SQLException e) {
		}
		try {
			mysql.createRuleSet("test");
		} catch (SQLException e) {
			fail("Error creating ruleset");
		}
	}

	@Test
	public void testDeleteRuleSet() {
		try {
			mysql.deleteRuleSet("test");
		} catch (SQLException e) {
		}
		try {
			mysql.createRuleSet("test");
		} catch (SQLException e) {
			fail("Error creating ruleset");
		}
		try {
			mysql.deleteRuleSet("test");
		} catch (SQLException e) {
			fail("Error creating ruleset");
		}
	}

	@Test
	public void testGetRuleSets() {
		String[] ruleSets = null;
		try {
			ruleSets = mysql.getRuleSets();
		} catch (SQLException e1) {
			fail("Couldn't get list of rulesets");
		}
		for (String ruleset: ruleSets) {
			try {
				mysql.deleteRuleSet(ruleset);
			} catch (SQLException e) {
				fail("Couldn't delete a ruleset");
			}
		}
		try {
			mysql.createRuleSet("test1");
			mysql.createRuleSet("test2");
		} catch (SQLException e) {
			fail("Error adding rulesets");
		}
		try {
			ruleSets = mysql.getRuleSets();
		} catch (SQLException e) {
			fail("Couldn't get list of rulesets");
		}
		if (ruleSets.length != 2)
			fail("Wrong ruleset list");
		for (String ruleset: ruleSets) {
			if (!ruleset.equals("test1") && !ruleset.equals("test2"))
				fail("Ruleset list isn't correct");
		}
	}

	@Test
	public void testGetLogs() {
		try {
			Log[] logs = mysql.getLogs(1, null, null, null, null, null);
		} catch (SQLException e) {
			fail("Couldn't retrive logs");
		}
	}

	@Test
	public void testGetGlobalLogs() {
		int size = -1;
		try {
			GlobalLog[] logs = mysql.getGlobalLogs(1);
			size = logs.length;
		} catch (SQLException e) {
			fail("Coulnd't get global log list");
		}
		try {
			mysql.addGlobalLog("Adding an test");
		} catch (SQLException e) {
		}
		try {
			GlobalLog[] logs = mysql.getGlobalLogs(1);
			if (size +1 != logs.length)
				fail("Wrong number of logs");
			if (!logs[logs.length-1].event.equals("Adding an test"))
				fail("Wrong log encountered");
		} catch (SQLException e) {
			fail("Coulnd't get global log list");
		}
	}

	@Test
	public void testAddGlobalLog() {
		try {
			mysql.addGlobalLog("Adding an test");
		} catch (SQLException e) {
			fail("Couldn't add an global log");
		}
	}

}
